import Logger from "@/utils/logger";

export default function validateConnection(e, graph) {
  Logger.log('开始验证连接合法性...')

  let sourceCellData = e.sourceCell.getData()
  let targetCellData = e.targetCell.getData()

  let sourceShape
  if (sourceCellData.inheritFromNode) {
    sourceShape = sourceCellData.inheritFromNode
  } else {
    sourceShape = e.sourceCell.shape
  }

  let targetShape
  if (targetCellData.inheritFromNode) {
    targetShape = targetCellData.inheritFromNode
  } else {
    targetShape = e.targetCell.shape
  }

  let beginValidate = validateRule[sourceShape] && validateRule[sourceShape]['shouldBegin']
  let endValidate = validateRule[targetShape] && validateRule[targetShape]['shouldEnd']

  if (beginValidate && !beginValidate(e, graph)) {
    return false
  }

  if (endValidate && !endValidate(e, graph)) {
    return false
  }

  return true
}

function _getCellInfo({edge, graph}) {
  try {
    const sourceCell = graph.getCellById(edge.source.cell)
    const sourceCellPortIds = sourceCell && sourceCell.getPorts().map(item => item.id) || []
    const sourceCellConnectedEdges = graph.getConnectedEdges(sourceCell) || []
    const sourceCellUsingPorts = sourceCellPortIds.filter(portId => {
      return sourceCellConnectedEdges.find(edge => edge.source.port === portId || edge.target.port === portId)
    })
    const sourceCellUnUsingPorts = sourceCellPortIds.filter(portId => !sourceCellUsingPorts.includes(portId))

    const targetCell = graph.getCellById(edge.target.cell)
    const targetCellPortIds = targetCell && targetCell.getPorts().map(item => item.id) || []
    const targetCellConnectedEdges = graph.getConnectedEdges(targetCell) || []
    const targetCellUsingPorts = targetCellPortIds.filter(portId => {
      return targetCellConnectedEdges.find(edge => edge.source.port === portId || edge.target.port === portId)
    })
    const targetCellUnUsingPorts = targetCellPortIds.filter(portId => !targetCellUsingPorts.includes(portId))

    return {
      sourceCell,
      sourceCellPortIds,
      sourceCellConnectedEdges,
      sourceCellUsingPorts,
      sourceCellUnUsingPorts,
      targetCell,
      targetCellPortIds,
      targetCellConnectedEdges,
      targetCellUsingPorts,
      targetCellUnUsingPorts
    }
  } catch (e) {
    console.error(e)
  }
}

export const validateRule = {
  start: {
    shouldBegin(e, graph) {
      const outgoingEdges = graph.getOutgoingEdges(e.sourceCell) || []
      // 仅允许创建一条边
      if (outgoingEdges.length > 1) {
        Logger.log('开始节点仅允许创建一条边')
        return false
      }

      return true
    },

    shouldEnd() {
      Logger.log('开始节点不能作为结束节点')
      return false
    }
  },

  condition: {
    shouldBegin(e, graph) {
      Logger.log('条件节点作为起点验证连接合法性', e)

      const incomingEdges = graph.getIncomingEdges(e.sourceCell) || []
      const isSameWithIncoming = !!incomingEdges.find(edge => edge.target.port === e.sourcePort)
      const outgoingEdges = graph.getOutgoingEdges(e.sourceCell) || []
      if (isSameWithIncoming) {
        Logger.log('当前连接点已作为入口使用')
        return false
      }

      if (outgoingEdges.length > 2) {
        Logger.log('条件节点的出线只能为两条')
        return false
      }

      const outgoingEdgesWithSamePort = outgoingEdges.filter(edge => edge.source.port === e.sourcePort).length > 1
      if (outgoingEdgesWithSamePort) {
        Logger.log('条件节点的出线使用了相同的PORT')
        return false
      }

      return true
    },

    shouldEnd(e, graph) {
      Logger.log('条件节点作为终点验证连接合法性')

      const outgoingEdges = graph.getOutgoingEdges(e.targetCell) || []
      const isSameWithOutGoing = outgoingEdges.find(edge => edge.getSourcePortId() === e.targetPort)
      if (isSameWithOutGoing) {
        Logger.log('当前PORT 已有出边')
        return false
      }

      return true
    }
  },

  switcherConcurrent: {
    shouldBegin(e, graph) {
      const incomingEdges = graph.getIncomingEdges(e.sourceCell) || []
      const isSameWithIncoming = !!incomingEdges.find(edge => edge.target.port === e.sourcePort)
      const outgoingEdges = graph.getOutgoingEdges(e.sourceCell) || []

      if (isSameWithIncoming) {
        Logger.log('当前连接点已作为入口使用')
        return false
      }

      if (outgoingEdges.length > 10) {
        Logger.log('已达连接上限：10')
        clearTimeout(this.debounceTimer)
        this.debounceTimer = setTimeout(() => {
          ElMessage.warning('设置分支必须在1~10条范围内，请重新设置')
        }, 500)
        return
      }

      return true
    },

    shouldEnd(e, graph) {
      const outgoingEdges = graph.getOutgoingEdges(e.targetCell) || []
      const isSameWithOutGoing = outgoingEdges.find(edge => edge.getSourcePortId() === e.targetPort)
      if (isSameWithOutGoing) {
        Logger.log('当前PORT 已有出边')
        return false
      }

      return true
    }
  },

  switcherCondition: {
    shouldBegin(e, graph) {
      return validateRule.switcherConcurrent.shouldBegin(e, graph)
    },

    shouldEnd(e, graph) {
      return validateRule.switcherConcurrent.shouldEnd(e, graph)
    }
  },

  abtest: {
    shouldBegin(e, graph) {
      return true
    },

    shouldEnd(e, graph) {
      const outgoingEdges = graph.getOutgoingEdges(e.targetCell) || []
      const isSameWithOutGoing = outgoingEdges.find(edge => edge.getSourcePortId() === e.targetPort)
      if (isSameWithOutGoing) {
        Logger.log('当前PORT 已有出边')
        return false
      }

      return true
    }
  },

  wait: {
    shouldBegin(e, graph) {
      const outgoingEdges = graph.getOutgoingEdges(e.sourceCell) || []

      // 仅允许创建一条边
      if (outgoingEdges.length > 1) {
        Logger.log('等待节点仅允许创建一条出边')
        return false
      }

      return true
    },

    shouldEnd(e, graph) {
      const outgoingEdges = graph.getOutgoingEdges(e.targetCell) || []
      const isSameWithOutGoing = outgoingEdges.find(edge => edge.getSourcePortId() === e.targetPort)
      if (isSameWithOutGoing) {
        Logger.log('当前PORT 已有出边')
        return false
      }
      return true
    }
  },

  end: {
    shouldBegin() {
      Logger.log('结束节点不能拉线')
      return false
    },

    shouldEnd(e) {
      return true
    }
  },

  action: {
    shouldBegin(e, graph) {
      const outgoingEdges = graph.getOutgoingEdges(e.sourceCell) || []
      // 仅允许创建一条边
      if (outgoingEdges.length > 1) {
        Logger.log('动作节点仅允许创建一条出边')
        return false
      }

      const incomingEdges = graph.getIncomingEdges(e.sourceCell) || []
      const isSameWithIncoming = !!incomingEdges.find(edge => edge.target.port === e.sourcePort)

      if (isSameWithIncoming) {
        Logger.log('当前连接点已作为入口使用')
        return false
      }

      return true
    },

    shouldEnd(e, graph) {
      const outgoingEdges = graph.getOutgoingEdges(e.targetCell) || []
      const isSameWithOutgoing = !!outgoingEdges.find(edge => edge.source.port === e.targetPort)

      if (isSameWithOutgoing) {
        Logger.log('当前连接点已作为出口使用')
        return false
      }

      return true
    }
  },

  event: {
    shouldBegin(e, graph) {
      const outgoingEdges = graph.getOutgoingEdges(e.sourceCell) || []
      // 仅允许创建一条边
      if (outgoingEdges.length > 1) {
        Logger.log('事件节点仅允许创建一条出边')
        return false
      }

      const incomingEdges = graph.getIncomingEdges(e.sourceCell) || []
      const isSameWithIncoming = !!incomingEdges.find(edge => edge.target.port === e.sourcePort)

      if (isSameWithIncoming) {
        Logger.log('当前连接点已作为入口使用')
        return false
      }

      return true
    },

    shouldEnd(e, graph) {
      const outgoingEdges = graph.getOutgoingEdges(e.targetCell) || []
      const isSameWithOutgoing = !!outgoingEdges.find(edge => edge.source.port === e.targetPort)

      if (isSameWithOutgoing) {
        Logger.log('当前连接点已作为出口使用')
        return false
      }

      return true
    }
  },

  placeholder: {
    shouldBegin(e, graph) {
      return false
    }
  }
}
